package com.ichir.projects.uiflow;

import java.util.Collections;
import java.util.Map;

import com.ichir.projects.uiflow.definition.FlowType;
import com.ichir.projects.uiflow.definition.IFlowPart;
import com.ichir.projects.uiflow.definition.IProgressAble;
import com.ichir.projects.uiflow.events.IUiPartListener;
import com.ichir.projects.uiflow.internal.decorators.UiActionDecorator;
import com.ichir.projects.uiflow.internal.executors.ExecutorsRegistry;
import com.ichir.projects.uiflow.internal.factories.UiPartFactory;
import com.ichir.projects.uiflow.internal.resolvers.TransitionResolver;
import com.ichir.projects.uiflow.ui.api.IUiAction;
import com.ichir.projects.uiflow.ui.api.IUiPart;

/**
 * Flow handler/manager class: handle events and transitions. Listener of all UI Events.
 * 
 * @author mahieddine
 * @since 1.0.0
 */
public class FlowHandler implements IUiPartListener {

	/**
	 * Application context.
	 */
	private ApplicationContext context;

	/**
	 * @return the context
	 */
	public ApplicationContext getContext() {
		return context;
	}

	/**
	 * @param context the context to set
	 */
	public void setContext(ApplicationContext context) {
		this.context = context;
	}

	/**
	 * Transition resolver.
	 */
	private TransitionResolver transitionResolver;
	
	@Override
	public void onEvent(IUiPart source, String eventId, Map<String, Object> attributes) {
		System.out.println(">> event source "+source.getClass()+", eventId: "+eventId);

		// on eventId null ==> do nothing
		if (eventId == null || eventId.isEmpty()) {
			System.out.println(">> eventId nul!!");
			return;
		}

		// Null safe attributes
		if (attributes == null) {
			System.out.println(">> attributes null!!");
			attributes = Collections.emptyMap();
		}

		// resolve transition: get next flow part
		IFlowPart next = transitionResolver.getNext(source, eventId);

		// set event source in application context
		context.setEventSource(source);
		// new instance from UI part
		try {
			IUiPart uiPart = UiPartFactory.getUiPart(next, context, attributes);
			if (FlowType.VIEW.equals(next.getType())) {
				// Add flow handler as a listener to view events
				if (uiPart instanceof AbstractUiView) {
					((AbstractUiView) uiPart).addHandledListener(this);
				}
				ExecutorsRegistry.execute(uiPart, FlowType.VIEW, context, attributes);
			} else {
				// decorate Action => to add listener
				UiActionDecorator decorator = new UiActionDecorator();
				decorator.setAction((IUiAction) uiPart);
				
				if (next instanceof IProgressAble) {
					IUiPart progress = UiPartFactory.getUiPart(((IProgressAble) next).getProgressUiPart(), context, attributes);
					decorator.setProgress(progress);
				}
				decorator.addHandledListener(this);
				ExecutorsRegistry.execute(decorator, FlowType.ACTION, context, attributes);
				//TODO resolve this
				//decorator.removeHandledListener(this);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public TransitionResolver getTransitionResolver() {
		return transitionResolver;
	}

	public void setTransitionResolver(TransitionResolver transitionResolver) {
		this.transitionResolver = transitionResolver;
	}
	
}
